package br.com.rapidrest.chain;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import br.com.rapidrest.annotation.SessionStored;
import br.com.rapidrest.exception.ChainException;
import br.com.rapidrest.exception.RequestException;
import br.com.rapidrest.request.RequestScope;
import br.com.rapidrest.util.MethodUtil;

public class BeanCommand implements Command {

	public static final String DEFAULT_INIT_METHOD = "init";

	public static final String PAGE_BEAN_SESSION_SUFFIX = "rapidrest.";

	@Override
	public void execute(Chain chain) throws ChainException {
		BasicChainContext context = (BasicChainContext) chain.getContext();
		RequestScope requestScope = context.getRequestScope();

		Class<?> beanClass = requestScope.getBeanClass();

		Object bean = null;

		HttpServletRequest req = context.getRequest();
		try {
			if (isSessionStored(beanClass)) {
				bean = retriveFromSession(req.getSession(), beanClass, true);
			} else {
				bean = beanClass.newInstance();
			}
		} catch (InstantiationException e) {
			throw new ChainException(e);
		} catch (IllegalAccessException e) {
			throw new ChainException(e);
		}
		context.setBean(bean);

		String methodName = requestScope.getMethodName();
		if (methodName == null) {
			methodName = DEFAULT_INIT_METHOD;
		}

		int paramsSize = 0;
		String[] params = requestScope.getParams();
		if (params != null) {
			paramsSize = params.length;
		}

		Method method = MethodUtil
				.findMethod(beanClass, methodName, paramsSize);
		// init method is optional!
		if (method == null && !methodName.equals(DEFAULT_INIT_METHOD)) {
			throw new RequestException("Method " + beanClass.getName() + "."
					+ methodName + " with " + paramsSize
					+ " parameters was not found.");
		}
		context.setMethod(method);

		chain.proceed();
	}

	protected boolean isSessionStored(Class<?> beanClass) {
		return beanClass.isAnnotationPresent(SessionStored.class);
	}

	protected Object retriveFromSession(HttpSession session, Class<?> beanClass,
			boolean create) throws InstantiationException,
			IllegalAccessException {
		String sessionAttr = PAGE_BEAN_SESSION_SUFFIX + beanClass.getName();
		Object bean = session.getAttribute(sessionAttr);
		if (bean == null && create) {
			bean = beanClass.newInstance();
			session.setAttribute(sessionAttr, bean);
		}
		return bean;
	}

}